/*
* Description: 负载探测
*/
#include "payload_sensor.h"
#include "sys_cpu_calc.h"
#include "log.h"
#include "performance/perf_scene.h"
#include "perf_counter.h"

namespace GUEST {
const std::string fileCompressDecompressStarting = "FileCompressDecompressStarting";
const std::string fileCompressDecompressFinished = "FileCompressDecompressFinished";

std::shared_ptr<WINCONTROL::SendToHost> PayloadSensor::GetSendToHost()
{
    return sendToHost;
}

void PayloadSensor::Init(std::shared_ptr<WINCONTROL::SendToHost> sendToHostSharedPtr)
{
    if (sendToHostSharedPtr == nullptr) {
        LOG_ERR("sendtoHostSharedPtr is null");
        return;
    }
    sendToHost = sendToHostSharedPtr;
    isInQuitProcess_.store(false);
    SetIsEnableCpuUpdate(true);
    isIncreasedFreq.store(false);
    filterMap_ = {};
    isAllowedRun_.store(false);
    int ret = SysCpuCalc::GetInstance().Init();
    if (ret) {
        LOG_INFO("VMAgent SysCpuCalc init success.");
        LoadSysCalThread();
    } else {
        LOG_ERR("VMAgent syscpucalc init failed!!!");
    }
    bool perfCounterLoad = PerfCounter::GetInstance().Init();
    if (perfCounterLoad) {
        LOG_INFO("VMAgent PerfCounter init success.");
    } else {
        LOG_ERR("VMAgent PerfCounter init failed!!!");
    }
    return;
}

void PayloadSensor::CompressDecompressApplicationFilter(unsigned long pid, std::string &name)
{
    if (appWhiteList.find(name) == appWhiteList.end()) {
        return;
    }
    LOG_INFO("Filter compress decompress application name : {}, pid : {}", name, pid);
    if (isInQuitProcess_.load()) {
        LOG_ERR("Filter pid error: program in quit process.");
        return;
    }
    filterMap_.emplace(pid, name);
    if (!isAllowedRun_.load()) {
        isAllowedRun_.store(true);
        std::unique_lock<std::mutex> lck(mtx_);
        LOG_INFO("Notify payload sensor thread.");
        cv_.notify_all();
    }
}

void PayloadSensor::CompressDecompressApplicationDeFilter(unsigned long pid)
{
    if (filterMap_.find(pid) == filterMap_.end()) {
        return;
    }
    LOG_INFO("Defilter compress decompress application pid : {}", pid);
    if (isInQuitProcess_.load()) {
        LOG_ERR("Defilter pid error: program in quit process.");
        return;
    }
    filterMap_.erase(pid);
    if (filterMap_.size() == 0) {
        LOG_INFO("Filter map collection is empty.");
        isAllowedRun_.store(false);
        if (PAYLOAD_SENSOR.GetIsIncreasedFreq()) {
            LOG_INFO("Execute invoke decrease frequency function.");
            InvokeDecreaseFreqFunction();
            PAYLOAD_SENSOR.SetIsIncreasedFreq(false);
        }
    }
}

void PayloadSensor::LoadSysCalThread()
{
    sysCpuCalThread = std::thread([this]() {
        LOG_INFO("VMAgent start SysCpuCalc collector thread successfully.");
        while (PAYLOAD_SENSOR.GetIsEnableCpuUpdate()) {
            // 等待1秒钟
            Sleep(PAYLOAD_SENSOR.cpuUpdateSleepTime);
            SysCpuCalc::GetInstance().CollectProcLoad();
            PAYLOAD_SENSOR.EnableIncreaseFrequency();
            std::unique_lock<std::mutex> lck(mtx_);
            cv_.wait(lck, [this] () {
                return isAllowedRun_.load();
            });
        }
        LOG_INFO("VMAgent SysCpuCalc collector thread quit successfully.");
    });
}

void PayloadSensor::EnableIncreaseFrequency()
{
    if (SysCpuCalc::GetInstance().FilterCompressDecompressActions() ||
        SysCpuCalc::GetInstance().FilterAPPResourceActions()) {
        if (!PAYLOAD_SENSOR.GetIsIncreasedFreq()) {
            LOG_INFO("starting increase frequency for file compress and decompres");
            InvokeIncreaseFreqFunction();
            PAYLOAD_SENSOR.SetIsIncreasedFreq(true);
        } else if (PAYLOAD_SENSOR.GetIsIncreasedFreq() && IsIncreaseFreqOverFoolProolTime()) {
            InvokeIncreaseFreqFunction();
            startTimestamp_ = GetSystemCurrentTimeInMilli();
        }
    } else {
        if (PAYLOAD_SENSOR.GetIsIncreasedFreq()) {
            LOG_INFO("finished increase frequency for file compress and decompres");
            InvokeDecreaseFreqFunction();
            PAYLOAD_SENSOR.SetIsIncreasedFreq(false);
        }
    }
}

void PayloadSensor::InvokeIncreaseFreqFunction()
{
    if (PAYLOAD_SENSOR.GetSendToHost() == nullptr) {
        LOG_ERR("sendtohost is null");
        return;
    }
    PAYLOAD_SENSOR.GetSendToHost()->SendPerfRequestToHost(PERF::appInit,
        fileCompressDecompressStarting, true);
    startTimestamp_ = GetSystemCurrentTimeInMilli();
}

void PayloadSensor::InvokeDecreaseFreqFunction()
{
    if (PAYLOAD_SENSOR.GetSendToHost() == nullptr) {
        LOG_ERR("sendtohost is null");
        return;
    }
    PAYLOAD_SENSOR.GetSendToHost()->SendPerfRequestToHost(PERF::appInit,
        fileCompressDecompressFinished, false);
}

void PayloadSensor::Quit()
{
    LOG_INFO("payload sensor start quit thread.");
    isInQuitProcess_.store(true);
    SetIsEnableCpuUpdate(false);
    if (!isAllowedRun_.load()) {
        isAllowedRun_.store(true);
        std::unique_lock<std::mutex> lck(mtx_);
        LOG_INFO("payload sensor quit process notify thread.");
        cv_.notify_all();
    }
    if (PAYLOAD_SENSOR.GetIsIncreasedFreq()) {
        LOG_INFO("payload sensor quit process invoke decrease frequency.");
        InvokeDecreaseFreqFunction();
    }
    if (sysCpuCalThread.joinable()) {
        LOG_INFO("payload sensor thread join.");
        sysCpuCalThread.join();
    }
    PerfCounter::GetInstance().Stop();
    LOG_INFO("payload sensor finished quit thread.");
}

void PayloadSensor::SetIsEnableCpuUpdate(const bool enableOrDisable)
{
    isEnableCpuUpdate.store(enableOrDisable);
}

bool PayloadSensor::GetIsEnableCpuUpdate()
{
    return isEnableCpuUpdate.load();
}

void PayloadSensor::SetIsIncreasedFreq(const bool isIncreased)
{
    isIncreasedFreq.store(isIncreased);
}

bool PayloadSensor::GetIsIncreasedFreq()
{
    return isIncreasedFreq.load();
}

bool PayloadSensor::IsIncreaseFreqOverFoolProolTime()
{
    bool isOver = false;
    int64_t curr = GetSystemCurrentTimeInMilli();
    if ((curr - startTimestamp_) > foolProolOperationTime_) {
        isOver = true;
        LOG_INFO("over increase freq fool prool time");
    }
    return isOver;
}

int64_t PayloadSensor::GetSystemCurrentTimeInMilli()
{
    int64_t time = std::chrono::duration_cast<std::chrono::milliseconds>(
        std::chrono::system_clock::now().time_since_epoch()).count();
    if (time < 0) {
        time = 0;
    }
    return time;
}
} // namespace GUEST